package com.pingpang.websocketchat;

import java.net.InetSocketAddress;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.pingpang.config.SpringContextUtil;
import com.pingpang.redis.RedisPre;
import com.pingpang.redis.service.RedisService;
import com.pingpang.service.UserMsgService;
import com.pingpang.service.UserService;
import com.pingpang.util.JsonFilterUtil;
import com.pingpang.util.StringUtil;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;

/** 
 * 处理TextWebSocketFrame
 */
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

	// public static ChannelGroup channels = new
	// DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
	private int count=0;
	private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled
			.unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat",
					CharsetUtil.UTF_8));  
	
	//用户信息处理
	private UserService userService=SpringContextUtil.getBean(UserService.class);
	
	//消息信息处理
	private UserMsgService userMsgService=SpringContextUtil.getBean(UserMsgService.class);
	
	//redis操作
	private RedisService redisService=SpringContextUtil.getBean(RedisService.class);
	
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { // (1)
		InetSocketAddress ipSocket = (InetSocketAddress)ctx.channel().remoteAddress();
	     String clientIp = ipSocket.getAddress().getHostAddress();
	     System.out.println("客户端ip地址："+clientIp);
		
		if("ping".equals(msg.text())) {
			ctx.channel().writeAndFlush(new TextWebSocketFrame("pong"));
			count=0;
			return;
		}
		
		if("Heartbeat".equals(msg.text())) {
			count=0;
			return;	
		}
		
		ObjectMapper mapper = new ObjectMapper();
		JsonFilterUtil.addFilterForMapper(mapper);
        Message message = mapper.readValue(msg.text(), Message.class);

        Channel incoming = ctx.channel();
		if (null != message) {
			
			//这里添加用户数据校验
			if(!ChatType.BIND.equals(message.getCmd())) {
				if(!incoming.equals(ChannelManager.getChannel(message.getFrom().getUserCode()))) {
					System.out.println("非登录用户操作:"+message.toString());
					return;
				}
				
				//当用户不是在线状态直接打回
				ChartUser fromUser=ChannelManager.getChartUser(message.getFrom().getUserCode());
				if(!ChatType.QUERY_USER.equals(message.getCmd()) && !"1".equals(fromUser.getUserStatus())){
					Channel cl=ChannelManager.getChannel(message.getFrom().getUserCode());
					
					//线上禁言
					message.setMsg("系统消息此用户已禁言");
					ChartUser admin=new ChartUser();
					admin.setUserCode("admin");
					admin.setUserName("管理员");
					message.setFrom(admin);
					message.setCmd("2");
					message.setCreateDate(StringUtil.format(new Date()));
					cl.writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
					
					return;
				}
				
			}
			
			//添加时间处理
			message.setCreateDate(StringUtil.format(new Date()));
			
			switch (message.getCmd()) {
			case ChatType.BIND:
				
				message.setFrom(userService.getUser(message.getFrom()));
				message.getFrom().setIp(clientIp);
				message.getFrom().setUserStatus("1");//设置为上线
                redisService.set(RedisPre.DB_USER+message.getFrom().getUserCode(), message.getFrom());
				ChannelManager.addChannel(message.getFrom(), incoming);
				
				/**
				 * 获取离线消息，并推送
				 */
				List<Message> outMsg=userMsgService.getUserOutMsg(message.getFrom());
				if(null!=outMsg && !outMsg.isEmpty()) {
					
					Set<String> messageIDs=new HashSet<String>();
					Map<String,Object> updateMap=new HashMap<String, Object>();
					updateMap.put("status", "1");
					updateMap.put("IP", clientIp);
	  				for(Message m : outMsg) {
	  					messageIDs.add(m.getId());
	  					m.setCmd("2");//当作离线通知和下线提醒
	  					incoming.writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(m)));		
					  }
	  				/**
	  				 * 更新数据状态
	  				 */
	  				updateMap.put("ids", messageIDs);
	  				userMsgService.upOutMsg(updateMap); 				
				}
				
				
				break;
			case ChatType.LEAVE:
				ChannelManager.removeChannelByCode(message.getFrom().getUserCode());
				break;
			case ChatType.SINGLE:
				// message.setMsg(HtmlUtils.htmlEscape(message.getMsg()));
				if (null != ChannelManager.getChannel(message.getAccept().getUserCode())) {
					//message.setFrom(ChannelManager.getChartUser(message.getFrom().getUserCode()));
					//message.setAccept(ChannelManager.getChartUser(message.getAccept().getUserCode()));
					
					//发送数据这里改为redis
					message.setFrom(userService.getUser(message.getFrom()));
					message.setAccept(userService.getUser(message.getAccept()));
					
					ChannelManager.getChannel(message.getAccept().getUserCode())
							.writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
					
					message.setStatus("1");
					userMsgService.addMsg(message);
				} else {
					message.setStatus("0");
					//message.setFrom(ChannelManager.getChartUser(message.getFrom().getUserCode()));
					message.setFrom(userService.getUser(message.getFrom()));
					message.setAccept(this.userService.getUser(message.getAccept()));
					userMsgService.addMsg(message);
					
					//提示给登录用户
					ChartUser from = message.getFrom();
					message.setFrom(message.getAccept());
					message.setAccept(from);
					message.setMsg("[" + message.getFrom().getUserName()+"("+message.getFrom().getUserCode()+")" + "]未上线");
					incoming.writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
				}
				
				break;
			case ChatType.GROUP:
				
				//message.setFrom(ChannelManager.getChartUser(message.getFrom().getUserCode()));
                  message.setFrom(userService.getUser(message.getFrom()));
                  
				if (!ChannelManager.isExit(message.getGroup(), message.getFrom().getUserCode())) {
					ChannelManager.addGroup(message.getGroup(), message.getFrom());
				}
				Set<ChartUser> user = ChannelManager.getGroupUser(message.getGroup());
				for (ChartUser str : user) {
					if (!str.equals(message.getFrom())) {
						ChannelManager.getChannel(str.getUserCode())
								.writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
					}
					message.setStatus("1");
					message.setAccept(str);//添加接收方数据
					userMsgService.addMsg(message);
				}
				break;
			case ChatType.QUERY_USER:
				message.setChatSet(ChannelManager.getAllUser());
				System.out.println("当前用户数量:"+message.getChatSet().size());
				incoming.writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
				break;
			default:
				System.out.println("未识别的命令");
				break;
			}
		}
		/*
		 * for (Channel channel : channels) { if (channel != incoming){
		 * channel.writeAndFlush(new TextWebSocketFrame("[" + incoming.remoteAddress() +
		 * "]" + msg.text())); } else { channel.writeAndFlush(new
		 * TextWebSocketFrame("[you]" + msg.text() )); } }
		 */
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent event = (IdleStateEvent) evt;
			System.out.println(ctx.channel().remoteAddress()+"超时次数:"+count);
			String type = "";
			if (event.state() == IdleState.READER_IDLE) {
				type = "read idle";
				count++;
				if(count>5) {
					  System.out.println("超时次数达到最大值了，断开连接");
		              ChannelManager.removeChannelByChannel(ctx.channel());
		              ctx.channel().close();
					}
			} else if (event.state() == IdleState.WRITER_IDLE) {
				type = "write idle";
				count=0;
			} else if (event.state() == IdleState.ALL_IDLE) {
				type = "all idle";
				count=0;
			}
			ctx.writeAndFlush(new TextWebSocketFrame("Heartbeat")).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
			System.out.println( ctx.channel().remoteAddress()+"超时类型：" + type);
		}
		super.userEventTriggered(ctx, evt);
	}
	
	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // (2)
		Channel incoming = ctx.channel();
		// Broadcast a message to multiple Channels
		// channels.writeAndFlush(new TextWebSocketFrame("[SERVER] - " +
		// incoming.remoteAddress() + " 加入"));

		// channels.add(incoming);
		System.out.println("Client:" + incoming.remoteAddress() + "加入");
	}

	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // (3)
		Channel incoming = ctx.channel();

		// Broadcast a message to multiple Channels
		// channels.writeAndFlush(new TextWebSocketFrame("[SERVER] - " +
		// incoming.remoteAddress() + " 离开"));

		System.out.println("Client:" + incoming.remoteAddress() + "离开");
		ChannelManager.removeChannelByChannel(incoming);
		// A closed Channel is automatically removed from ChannelGroup,
		// so there is no need to do "channels.remove(ctx.channel());"
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
		Channel incoming = ctx.channel();
		System.out.println("Client:" + incoming.remoteAddress() + "在线");
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
		Channel incoming = ctx.channel();
		System.out.println("Client:" + incoming.remoteAddress() + "掉线");
		ChannelManager.removeChannelByChannel(incoming);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) // (7)
			throws Exception {
		Channel incoming = ctx.channel();
		System.out.println("Client:" + incoming.remoteAddress() + "异常");
		// 当出现异常就关闭连接
		cause.printStackTrace();
		ctx.close();
	}

}
